home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / compress / unzip531.zip / human68k / human68k.c < prev    next >
C/C++ Source or Header  |  1997-02-17  |  24KB  |  715 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   human68k.c
  4.  
  5.   Human68K-specific routines for use with Info-ZIP's UnZip 5.1 and later.
  6.  
  7.   Contains:  do_wild()
  8.              mapattr()
  9.              mapname()
  10.              checkdir()
  11.              close_outfile()
  12.              version()
  13.              TwentyOne()
  14.              normalize_name()
  15.  
  16.   ---------------------------------------------------------------------------*/
  17.  
  18.  
  19. #include <dirent.h>
  20. #include <sys/dos.h>
  21. #include <sys/xunistd.h>
  22. #include <jstring.h>
  23. #define UNZIP_INTERNAL
  24. #include "unzip.h"
  25.  
  26.  
  27. static void normalize_name(char *);
  28.  
  29. static int created_dir;        /* used in mapname(), checkdir() */
  30. static int renamed_fullpath;   /* ditto */
  31.  
  32. #ifndef SFX
  33.  
  34. /**********************/
  35. /* Function do_wild() */
  36. /**********************/
  37.  
  38. char *do_wild(__G__ wildspec)
  39.     __GDEF
  40.     char *wildspec;         /* only used first time on a given dir */
  41. {
  42.     static DIR *dir = NULL;
  43.     static char *dirname, *wildname, matchname[FILNAMSIZ];
  44.     static int firstcall=TRUE, have_dirname, dirnamelen;
  45.     struct dirent *file;
  46.  
  47.  
  48.     /* Even when we're just returning wildspec, we *always* do so in
  49.      * matchname[]--calling routine is allowed to append four characters
  50.      * to the returned string, and wildspec may be a pointer to argv[].
  51.      */
  52.     if (firstcall) {        /* first call:  must initialize everything */
  53.         firstcall = FALSE;
  54.  
  55.         /* break the wildspec into a directory part and a wildcard filename */
  56.         if ((wildname = strrchr(wildspec, '/')) == NULL) {
  57.             dirname = ".";
  58.             dirnamelen = 1;
  59.             have_dirname = FALSE;
  60.             wildname = wildspec;
  61.         } else {
  62.             ++wildname;     /* point at character after '/' */
  63.             dirnamelen = wildname - wildspec;
  64.             if ((dirname = (char *)malloc(dirnamelen+1)) == NULL) {
  65.                 Info(slide, 1, ((char *)slide,
  66.                   "warning:  can't allocate wildcard buffers\n"));
  67.                 strcpy(matchname, wildspec);
  68.                 return matchname;   /* but maybe filespec was not a wildcard */
  69.             }
  70.             strncpy(dirname, wildspec, dirnamelen);
  71.             dirname[dirnamelen] = '\0';   /* terminate for strcpy below */
  72.             have_dirname = TRUE;
  73.         }
  74.  
  75.         if ((dir = opendir(dirname)) != NULL) {
  76.             while ((file = readdir(dir)) != NULL) {
  77.                 if (file->d_name[0] == '.' && wildname[0] != '.')
  78.                     continue;  /* Unix:  '*' and '?' do not match leading dot */
  79.                 if (match(file->d_name, wildname, 0)) {  /* 0 == case sens. */
  80.                     if (have_dirname) {
  81.                         strcpy(matchname, dirname);
  82.                         strcpy(matchname+dirnamelen, file->d_name);
  83.                     } else
  84.                         strcpy(matchname, file->d_name);
  85.                     return matchname;
  86.                 }
  87.             }
  88.             /* if we get to here directory is exhausted, so close it */
  89.             closedir(dir);
  90.             dir = NULL;
  91.         }
  92.  
  93.         /* return the raw wildspec in case that works (e.g., directory not
  94.          * searchable, but filespec was not wild and file is readable) */
  95.         strcpy(matchname, wildspec);
  96.         return matchname;
  97.     }
  98.  
  99.     /* last time through, might have failed opendir but returned raw wildspec */
  100.     if (dir == NULL) {
  101.         firstcall = TRUE;  /* nothing left to try--reset for new wildspec */
  102.         if (have_dirname)
  103.             free(dirname);
  104.         return (char *)NULL;
  105.     }
  106.  
  107.     /* If we've gotten this far, we've read and matched at least one entry
  108.      * successfully (in a previous call), so dirname has been copied into
  109.      * matchname already.
  110.      */
  111.     while ((file = readdir(dir)) != NULL)
  112.         if (match(file->d_name, wildname, 0)) {   /* 0 == don't ignore case */
  113.             if (have_dirname) {
  114.                 /* strcpy(matchname, dirname); */
  115.                 strcpy(matchname+dirnamelen, file->d_name);
  116.             } else
  117.                 strcpy(matchname, file->d_name);
  118.             return matchname;
  119.         }
  120.  
  121.     closedir(dir);     /* have read at least one dir entry; nothing left */
  122.     dir = NULL;
  123.     firstcall = TRUE;  /* reset for new wildspec */
  124.     if (have_dirname)
  125.         free(dirname);
  126.     return (char *)NULL;
  127.  
  128. } /* end function do_wild() */
  129.  
  130. #endif /* !SFX */
  131.  
  132.  
  133.  
  134.  
  135. /**********************/
  136. /* Function mapattr() */
  137. /**********************/
  138.  
  139. int mapattr(__G)
  140.     __GDEF
  141. {
  142.     ulg  tmp = G.crec.external_file_attributes;
  143.  
  144.     if (G.pInfo->hostnum == UNIX_ || G.pInfo->hostnum == VMS_)
  145.         G.pInfo->file_attr = _mode2dos(tmp >> 16);
  146.     else
  147.         /* set archive bit (file is not backed up): */
  148.         G.pInfo->file_attr = (unsigned)(G.crec.external_file_attributes|32) &
  149.           0xff;
  150.     return 0;
  151.  
  152. } /* end function mapattr() */
  153.  
  154.  
  155.  
  156.  
  157.  
  158. /**********************/
  159. /* Function mapname() */
  160. /**********************/
  161.                              /* return 0 if no error, 1 if caution (filename */
  162. int mapname(__G__ renamed)   /*  truncated), 2 if warning (skip file because */
  163.     __GDEF                   /*  dir doesn't exist), 3 if error (skip file), */
  164.     int renamed;             /*  or 10 if out of memory (skip file) */
  165. {                            /*  [also IZ_VOL_LABEL, IZ_CREATED_DIR] */
  166.     char pathcomp[FILNAMSIZ];    /* path-component buffer */
  167.     char *pp, *cp=(char *)NULL;  /* character pointers */
  168.     char *lastsemi=(char *)NULL; /* pointer to last semi-colon in pathcomp */
  169.     int quote = FALSE;           /* flags */
  170.     int error = 0;
  171.     register unsigned workch;    /* hold the character being tested */
  172.  
  173.  
  174. /*---------------------------------------------------------------------------
  175.     Initialize various pointers and counters and stuff.
  176.   ---------------------------------------------------------------------------*/
  177.  
  178.     if (G.pInfo->vollabel)
  179.         return IZ_VOL_LABEL;    /* can't set disk volume labels in Unix */
  180.  
  181.     /* can create path as long as not just freshening, or if user told us */
  182.     G.create_dirs = (!G.fflag || renamed);
  183.  
  184.     created_dir = FALSE;        /* not yet */
  185.  
  186.     /* user gave full pathname:  don't prepend rootpath */
  187.     renamed_fullpath = (renamed && (*filename == '/'));
  188.  
  189.     if (checkdir(__G__ (char *)NULL, INIT) == 10)
  190.         return 10;              /* initialize path buffer, unless no memory */
  191.  
  192.     *pathcomp = '\0';           /* initialize translation buffer */
  193.     pp = pathcomp;              /* point to translation buffer */
  194.     if (G.jflag)                /* junking directories */
  195.         cp = (char *)strrchr(G.filename, '/');
  196.     if (cp == NULL)             /* no '/' or not junking dirs */
  197.         cp = G.filename;        /* point to internal zipfile-member pathname */
  198.     else
  199.         ++cp;                   /* point to start of last component of path */
  200.  
  201. /*---------------------------------------------------------------------------
  202.     Begin main loop through characters in filename.
  203.   ---------------------------------------------------------------------------*/
  204.  
  205.     while ((workch = (uch)*cp++) != 0) {
  206.         if (iskanji(workch)) {
  207.             *pp++ = (char)workch;
  208.             quote = TRUE;
  209.         } else if (quote) {                 /* if character quoted, */
  210.             *pp++ = (char)workch;    /*  include it literally */
  211.             quote = FALSE;
  212.         } else
  213.             switch (workch) {
  214.             case '/':             /* can assume -j flag not given */
  215.                 *pp = '\0';
  216.                 if ((error = checkdir(__G__ pathcomp, APPEND_DIR)) > 1)
  217.                     return error;
  218.                 pp = pathcomp;    /* reset conversion buffer for next piece */
  219.                 lastsemi = NULL;  /* leave directory semi-colons alone */
  220.                 break;
  221.  
  222.             case ';':             /* VMS version (or DEC-20 attrib?) */
  223.                 lastsemi = pp;         /* keep for now; remove VMS ";##" */
  224.                 *pp++ = (char)workch;  /*  later, if requested */
  225.                 break;
  226.  
  227.             case '\026':          /* control-V quote for special chars */
  228.                 quote = TRUE;     /* set flag for next character */
  229.                 break;
  230.  
  231.             case ' ':             /* change spaces to underscore under */
  232.                 *pp++ = '_';      /*  MTS; leave as spaces under Unix */
  233.                 break;
  234.  
  235.             default:
  236.                 /* allow European characters in filenames: */
  237.                 if (isprint(workch) || (128 <= workch && workch <= 254))
  238.                     *pp++ = (char)workch;
  239.             } /* end switch */
  240.  
  241.     } /* end while loop */
  242.  
  243.     *pp = '\0';                   /* done with pathcomp:  terminate it */
  244.  
  245.     /* if not saving them, remove VMS version numbers (appended ";###") */
  246.     if (!G.V_flag && lastsemi) {
  247.         pp = lastsemi + 1;
  248.         while (isdigit((uch)(*pp)))
  249.             ++pp;
  250.         if (*pp == '\0')          /* only digits between ';' and end:  nuke */
  251.             *lastsemi = '\0';
  252.     }
  253.  
  254. /*---------------------------------------------------------------------------
  255.     Report if directory was created (and no file to create:  filename ended
  256.     in '/'), check name to be sure it exists, and combine path and name be-
  257.     fore exiting.
  258.   ---------------------------------------------------------------------------*/
  259.  
  260.     if (G.filename[strlen(G.filename) - 1] == '/') {
  261.         checkdir(__G__ G.filename, GETPATH);
  262.         if (created_dir) {
  263.             if (QCOND2) {
  264.                 Info(slide, 0, ((char *)slide, "   creating: %s\n",
  265.                   G.filename));
  266.             }
  267.             return IZ_CREATED_DIR;   /* set dir time (note trailing '/') */
  268.         }
  269.         return 2;   /* dir existed already; don't look for data to extract */
  270.     }
  271.  
  272.     if (*pathcomp == '\0') {
  273.         Info(slide, 1, ((char *)slide, "mapname:  conversion of %s failed\n",
  274.           G.filename));
  275.         return 3;
  276.     }
  277.  
  278.     checkdir(__G__ pathcomp, APPEND_NAME);  /* returns 1 if truncated: care? */
  279.     checkdir(__G__ G.filename, GETPATH);
  280.  
  281.     return error;
  282.  
  283. } /* end function mapname() */
  284.  
  285.  
  286.  
  287.  
  288.  
  289. /***********************/
  290. /* Function checkdir() */
  291. /***********************/
  292.  
  293. int checkdir(__G__ pathcomp, flag)
  294.     __GDEF
  295.     char *pathcomp;
  296.     int flag;
  297. /*
  298.  * returns:  1 - (on APPEND_NAME) truncated filename
  299.  *           2 - path doesn't exist, not allowed to create
  300.  *           3 - path doesn't exist, tried to create and failed; or
  301.  *               path exists and is not a directory, but is supposed to be
  302.  *           4 - path is too long
  303.  *          10 - can't allocate memory for filename buffers
  304.  */
  305. {
  306.     static int rootlen = 0;   /* length of rootpath */
  307.     static char *rootpath;    /* user's "extract-to" directory */
  308.     static char *buildpath;   /* full path (so far) to extracted file */
  309.     static char *end;         /* pointer to end of buildpath ('\0') */
  310.  
  311. #   define FN_MASK   7
  312. #   define FUNCTION  (flag & FN_MASK)
  313.  
  314.  
  315.  
  316. /*---------------------------------------------------------------------------
  317.     APPEND_DIR:  append the path component to the path being built and check
  318.     for its existence.  If doesn't exist and we are creating directories, do
  319.     so for this one; else signal success or error as appropriate.
  320.   ---------------------------------------------------------------------------*/
  321.  
  322.     if (FUNCTION == APPEND_DIR) {
  323.         int too_long = FALSE;
  324.         char *old_end = end;
  325.  
  326.         Trace((stderr, "appending dir segment [%s]\n", pathcomp));
  327.         while ((*end = *pathcomp++) != '\0')
  328.             ++end;
  329.         normalize_name(old_end);
  330.  
  331.         /* GRR:  could do better check, see if overrunning buffer as we go:
  332.          * check end-buildpath after each append, set warning variable if
  333.          * within 20 of FILNAMSIZ; then if var set, do careful check when
  334.          * appending.  Clear variable when begin new path. */
  335.  
  336.         if ((end-buildpath) > FILNAMSIZ-3)  /* need '/', one-char name, '\0' */
  337.             too_long = TRUE;                /* check if extracting directory? */
  338.         if (stat(buildpath, &G.statbuf))    /* path doesn't exist */
  339.         {
  340.             if (!G.create_dirs) { /* told not to create (freshening) */
  341.                 free(buildpath);
  342.                 return 2;         /* path doesn't exist:  nothing to do */
  343.             }
  344.             if (too_long) {
  345.                 Info(slide, 1, ((char *)slide,
  346.                   "checkdir error:  path too long: %s\n",
  347.                   buildpath));
  348.                 free(buildpath);
  349.                 return 4;         /* no room for filenames:  fatal */
  350.             }
  351.             if (MKDIR(buildpath, 0666) == -1) {   /* create the directory */
  352.                 Info(slide, 1, ((char *)slide,
  353.                   "checkdir error:  can't create %s\n\
  354.                  unable to process %s.\n",
  355.                   buildpath, G.filename));
  356.                 free(buildpath);
  357.                 return 3;      /* path didn't exist, tried to create, failed */
  358.             }
  359.             created_dir = TRUE;
  360.         } else if (!S_ISDIR(G.statbuf.st_mode)) {
  361.             Info(slide, 1, ((char *)slide,
  362.               "checkdir error:  %s exists but is not directory\n\
  363.                  unable to process %s.\n",
  364.               buildpath, G.filename));
  365.             free(buildpath);
  366.             return 3;          /* path existed but wasn't dir */
  367.         }
  368.         if (too_long) {
  369.             Info(slide, 1, ((char *)slide,
  370.               "checkdir error:  path too long: %s\n",
  371.               buildpath));
  372.             free(buildpath);
  373.             return 4;         /* no room for filenames:  fatal */
  374.         }
  375.         *end++ = '/';
  376.         *end = '\0';
  377.         Trace((stderr, "buildpath now = [%s]\n", buildpath));
  378.         return 0;
  379.  
  380.     } /* end if (FUNCTION == APPEND_DIR) */
  381.  
  382. /*---------------------------------------------------------------------------
  383.     GETPATH:  copy full path to the string pointed at by pathcomp, and free
  384.     buildpath.
  385.   ---------------------------------------------------------------------------*/
  386.  
  387.     if (FUNCTION == GETPATH) {
  388.         strcpy(pathcomp, buildpath);
  389.         Trace((stderr, "getting and freeing path [%s]\n", pathcomp));
  390.         free(buildpath);
  391.         buildpath = end = (char *)NULL;
  392.         return 0;
  393.     }
  394.  
  395. /*---------------------------------------------------------------------------
  396.     APPEND_NAME:  assume the path component is the filename; append it and
  397.     return without checking for existence.
  398.   ---------------------------------------------------------------------------*/
  399.  
  400.     if (FUNCTION == APPEND_NAME) {
  401.         char *old_end = end;
  402.  
  403.         Trace((stderr, "appending filename [%s]\n", pathcomp));
  404.         while ((*end = *pathcomp++) != '\0') {
  405.             ++end;
  406.             normalize_name(old_end);
  407.             if ((end-buildpath) >= FILNAMSIZ) {
  408.                 *--end = '\0';
  409.                 Info(slide, 1, ((char *)slide,
  410.                   "checkdir warning:  path too long; truncating\n\
  411.                    %s\n                -> %s\n",
  412.                   G.filename, buildpath));
  413.                 return 1;   /* filename truncated */
  414.             }
  415.         }
  416.         Trace((stderr, "buildpath now = [%s]\n", buildpath));
  417.         return 0;  /* could check for existence here, prompt for new name... */
  418.     }
  419.  
  420. /*---------------------------------------------------------------------------
  421.     INIT:  allocate and initialize buffer space for the file currently being
  422.     extracted.  If file was renamed with an absolute path, don't prepend the
  423.     extract-to path.
  424.   ---------------------------------------------------------------------------*/
  425.  
  426. /* GRR:  for VMS and TOPS-20, add up to 13 to strlen */
  427.  
  428.     if (FUNCTION == INIT) {
  429.         Trace((stderr, "initializing buildpath to "));
  430.         if ((buildpath = (char *)malloc(strlen(G.filename)+rootlen+1)) ==
  431.             (char *)NULL)
  432.             return 10;
  433.         if ((rootlen > 0) && !renamed_fullpath) {
  434.             strcpy(buildpath, rootpath);
  435.             end = buildpath + rootlen;
  436.         } else {
  437.             *buildpath = '\0';
  438.             end = buildpath;
  439.         }
  440.         Trace((stderr, "[%s]\n", buildpath));
  441.         return 0;
  442.     }
  443.  
  444. /*---------------------------------------------------------------------------
  445.     ROOT:  if appropriate, store the path in rootpath and create it if neces-
  446.     sary; else assume it's a zipfile member and return.  This path segment
  447.     gets used in extracting all members from every zipfile specified on the
  448.     command line.
  449.   ---------------------------------------------------------------------------*/
  450.  
  451. #if (!defined(SFX) || defined(SFX_EXDIR))
  452.     if (FUNCTION == ROOT) {
  453.         Trace((stderr, "initializing root path to [%s]\n", pathcomp));
  454.         if (pathcomp == (char *)NULL) {
  455.             rootlen = 0;
  456.             return 0;
  457.         }
  458.         if ((rootlen = strlen(pathcomp)) > 0) {
  459.             int had_trailing_pathsep=FALSE;
  460.  
  461.             if (pathcomp[rootlen-1] == '/') {
  462.                 pathcomp[--rootlen] = '\0';
  463.                 had_trailing_pathsep = TRUE;
  464.             }
  465.             if (rootlen > 0 && (SSTAT(pathcomp, &G.statbuf) ||
  466.                 !S_ISDIR(G.statbuf.st_mode)))          /* path does not exist */
  467.             {
  468.                 if (!G.create_dirs /* || iswild(pathcomp) */ ) {
  469.                     rootlen = 0;
  470.                     return 2;   /* skip (or treat as stored file) */
  471.                 }
  472.                 /* create the directory (could add loop here to scan pathcomp
  473.                  * and create more than one level, but why really necessary?) */
  474.                 if (MKDIR(pathcomp, 0777) == -1) {
  475.                     Info(slide, 1, ((char *)slide,
  476.                       "checkdir:  can't create extraction directory: %s\n",
  477.                       pathcomp));
  478.                     rootlen = 0;   /* path didn't exist, tried to create, and */
  479.                     return 3;  /* failed:  file exists, or 2+ levels required */
  480.                 }
  481.             }
  482.             if ((rootpath = (char *)malloc(rootlen+2)) == NULL) {
  483.                 rootlen = 0;
  484.                 return 10;
  485.             }
  486.             strcpy(rootpath, pathcomp);
  487.             rootpath[rootlen++] = '/';
  488.             rootpath[rootlen] = '\0';
  489.             Trace((stderr, "rootpath now = [%s]\n", rootpath));
  490.         }
  491.         return 0;
  492.     }
  493. #endif /* !SFX || SFX_EXDIR */
  494.  
  495. /*---------------------------------------------------------------------------
  496.     END:  free rootpath, immediately prior to program exit.
  497.   ---------------------------------------------------------------------------*/
  498.  
  499.     if (FUNCTION == END) {
  500.         Trace((stderr, "freeing rootpath\n"));
  501.         if (rootlen > 0)
  502.             free(rootpath);
  503.         return 0;
  504.     }
  505.  
  506.     return 99;  /* should never reach */
  507.  
  508. } /* end function checkdir() */
  509.  
  510.  
  511.  
  512.  
  513.  
  514. /****************************/
  515. /* Function close_outfile() */
  516. /****************************/
  517.  
  518. void close_outfile(__G)
  519.     __GDEF
  520. {
  521. #ifdef USE_EF_UT_TIME
  522.     iztimes z_utime;
  523.  
  524.     /* The following DOS date/time structure is machine dependent as it
  525.      * assumes "little endian" byte order. For MSDOS specific code, which
  526.      * is run on ix86 CPUs (or emulators), this assumption is valid; but
  527.      * care should be taken when using this code as template for other ports.
  528.      */
  529.     union {
  530.         ulg z_dostime;
  531.         struct {                /* date and time words */
  532.             union {             /* DOS file modification time word */
  533.                 ush ztime;
  534.                 struct {
  535.                     unsigned zt_se : 5;
  536.                     unsigned zt_mi : 6;
  537.                     unsigned zt_hr : 5;
  538.                 } _tf;
  539.             } _t;
  540.             union {             /* DOS file modification date word */
  541.                 ush zdate;
  542.                 struct {
  543.                     unsigned zd_dy : 5;
  544.                     unsigned zd_mo : 4;
  545.                     unsigned zd_yr : 7;
  546.                 } _df;
  547.             } _d;
  548.         } zt;
  549.     } dos_dt;
  550. #endif /* USE_EF_UT_TIME */
  551.  
  552.     if (G.cflag) {
  553.         fclose(G.outfile);
  554.         return;
  555.     }
  556.  
  557. #ifdef USE_EF_UT_TIME
  558.     if (G.extra_field &&
  559.         (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0,
  560.                           &z_utime, NULL) & EB_UT_FL_MTIME)) {
  561.         struct tm *t;
  562.  
  563.         TTrace((stderr, "close_outfile:  Unix e.f. modif. time = %ld\n",
  564.           z_utime.mtime));
  565.         /* round up to even seconds */
  566.         z_utime.mtime = (z_utime.mtime + 1) & (~1);
  567.         t = localtime(&(z_utime.mtime));
  568.         if (t->tm_year < 80) {
  569.             dos_dt.zt._t._tf.zt_se = 0;
  570.             dos_dt.zt._t._tf.zt_mi = 0;
  571.             dos_dt.zt._t._tf.zt_hr = 0;
  572.             dos_dt.zt._d._df.zd_dy = 1;
  573.             dos_dt.zt._d._df.zd_mo = 1;
  574.             dos_dt.zt._d._df.zd_yr = 0;
  575.         } else {
  576.             dos_dt.zt._t._tf.zt_se = t->tm_sec >> 1;
  577.             dos_dt.zt._t._tf.zt_mi = t->tm_min;
  578.             dos_dt.zt._t._tf.zt_hr = t->tm_hour;
  579.             dos_dt.zt._d._df.zd_dy = t->tm_mday;
  580.             dos_dt.zt._d._df.zd_mo = t->tm_mon + 1;
  581.             dos_dt.zt._d._df.zd_yr = t->tm_year - 80;
  582.         }
  583.     } else {
  584.         dos_dt.zt._t.ztime = G.lrec.last_mod_file_time;
  585.         dos_dt.zt._d.zdate = G.lrec.last_mod_file_date;
  586.     }
  587.     _dos_filedate(fileno(G.outfile), dos_dt.z_dostime);
  588. #else /* !USE_EF_UT_TIME */
  589.     _dos_filedate(fileno(G.outfile),
  590.       (ulg)G.lrec.last_mod_file_date << 16 | G.lrec.last_mod_file_time);
  591. #endif /* ?USE_EF_UT_TIME */
  592.  
  593.     fclose(G.outfile);
  594.  
  595.     _dos_chmod(G.filename, G.pInfo->file_attr);
  596.  
  597. } /* end function close_outfile() */
  598.  
  599.  
  600.  
  601.  
  602. #ifndef SFX
  603.  
  604. /************************/
  605. /*  Function version()  */
  606. /************************/
  607.  
  608. void version(__G)
  609.     __GDEF
  610. {
  611.     int len;
  612. #if 0
  613.     char buf[40];
  614. #endif
  615.  
  616.     len = sprintf((char *)slide, LoadFarString(CompiledWith),
  617.  
  618. #ifdef __GNUC__
  619.       "gcc ", __VERSION__,
  620. #else
  621. #  if 0
  622.       "cc ", (sprintf(buf, " version %d", _RELEASE), buf),
  623. #  else
  624.       "unknown compiler", "",
  625. #  endif
  626. #endif
  627.  
  628.       "Human68k", " (X68000)",
  629.  
  630. #ifdef __DATE__
  631.       " on ", __DATE__
  632. #else
  633.       "", ""
  634. #endif
  635.       );
  636.  
  637.     (*G.message)((zvoid *)&G, slide, (ulg)len, 0);
  638.  
  639. } /* end function version() */
  640.  
  641. #endif /* !SFX */
  642.  
  643.  
  644.  
  645.  
  646.  
  647. /* Human68K-specific routines */
  648.  
  649. #define VALID_CHAR "&#()@_^{}!"
  650.  
  651. extern ulg TwentyOneOptions(void);
  652.  
  653. static int multi_period = 0;
  654. static int special_char = 0;
  655.  
  656. void
  657. InitTwentyOne(void)
  658. {
  659.     ulg stat;
  660.  
  661.     stat = TwentyOneOptions();
  662.     if (stat == 0 || stat == (unsigned long) -1) {
  663.         special_char = 0;
  664.         multi_period = 0;
  665.         return;
  666.     }
  667.     if (stat & (1UL << 29))
  668.         special_char = 1;
  669.     if (stat & (1UL << 28))
  670.         multi_period = 1;
  671. }
  672.  
  673. static void
  674. normalize_name(char *name)
  675. {
  676.     char *dot;
  677.     char *p;
  678.  
  679.     if (strlen(name) > 18) {    /* too long */
  680.         char base[18 + 1];
  681.         char ext[4 + 1];
  682.  
  683.         if ((dot = jstrrchr(name, '.')) != NULL)
  684.             *dot = '\0';
  685.         strncpy(base, name, 18);
  686.         base[18] = '\0';
  687.         if (dot) {
  688.             *dot = '.';
  689.             strncpy(ext, dot, 4);
  690.             ext[4] = '\0';
  691.         } else
  692.             *ext = '\0';
  693.         strcpy(name, base);
  694.         strcat(name, ext);
  695.     }
  696.     dot = NULL;
  697.     for (p = name; *p; p++) {
  698.         if (iskanji((unsigned char)*p) && p[1] != '\0')
  699.             p++;
  700.         else if (*p == '.') {
  701.             if (!multi_period) {
  702.                 dot = p;
  703.                 *p = '_';
  704.             }
  705.         } else if (!special_char && !isalnum (*p)
  706.                    && strchr(VALID_CHAR, *p) == NULL)
  707.             *p = '_';
  708.     }
  709.     if (dot != NULL) {
  710.         *dot = '.';
  711.         if (strlen(dot) > 4)
  712.             dot[4] = '\0';
  713.     }
  714. }
  715.